#!/usr/bin/env python
from random import random

# Dont forget to add comment !!!
# try commit again

class Node(object):
    def __init__(self,name):
        self.Name = name
        self.Visited = False
        self.NNeighbours = 0
        self.LinkWeight = []
        self.NeighbourIndex = []
        
    def Set_Visited(self):
        self.Visited = True
        
    def Unvisited(self):
        self.Visited = False
        
    def __str__(self):
        s = ''
        s += 'Name: ' + str(self.Name) + "\n"
        s += 'Visited: ' + str(self.Visited) + "\n"
        s += 'Number of Neighbours: ' + str(self.NNeighbours) + "\n"
        s += 'LinkWeight: ' + str(self.LinkWeight) + "\n"
        s += 'Neighbour Index: ' + str(self.NeighbourIndex)
        return s
        
    def __eq__(self, other):
        return self.Visited == other

    def __ne__(self, other):
        return not self.__eq__(other)

class Graph(object):
    def __init__(self, N, minL, maxL, minP, maxP):
        self.N = N
        self.minL = minL
        self.maxL = maxL
        self.minP = minP
        self.maxP = maxP
        self.Graph = []
        self.numL = None
        self.tpL = None
        self.NodeList = []
        
    def GenerateNodeList(self):
    
        for i in range(0,self.N):
            self.NodeList.append(Node(str(i)))  
            for j in range(0,self.N):
                if self.Graph[i][j] > 0:
                    self.NodeList[i].NNeighbours += 1
                    self.NodeList[i].NeighbourIndex.append(j)
                    self.NodeList[i].LinkWeight.append(self.Graph[i][j])
    
    def Dijkstra(self, src, dst):
        D = [0 for i in xrange(self.N)]
        V = [0 for i in xrange(self.N)]
        C = [0 for i in xrange(self.N)]
        
        for n in range(0,self.N-1):
            D[n] = self.Graph[src][n]
            C[n] = src
            V[n] = False
        V[src] = True
        
        nVisited = 1
        while nVisisted < self.N:
            closest = 0
    
    
    def DFS_R(self,Node_List,Source,Destination,path,p):
        if Node_List[Source].Visited:
            return False
        Node_List[Source].Set_Visited()

        find = False
        k = 0    
        v = 0 
        while k <= Node_List[Source].NNeighbours and find == False:
            v = Node_List[Source].NeighbourIndex[k]
            if Node_List[v].Name == Destination:
                find = True
                path[p+1] = Node_List[v].Name
            else:
                find = self.DFS(Node_List,v,Destination,path,p+1)
            if find == False:
                 k = k+1
        if find == True:
            Node_List[Source].Visited()
            path[p] = Node_List[source].Name
            return True
            
            
    def DFS(self,Node_List,Source,Destination):
        if Destination > (len(Node_List)-1):
            print "!!! Destination is not in Node List !!!"
            return False        
            
        if Node_List[Source].Visited:
            print "!!! Node have already be visited !!!"
            return False
        Node_List[Source].Set_Visited()    

    
    def BFS(self,Node_List,Source,Destination):
        if Destination > (len(Node_List)-1):
            print "!!! Destination is not in Node List !!!"
            return False
            
        if Node_List[Source].Visited:
            print "!!! Node have already be visited !!!"
            return False
        Node_List[Source].Set_Visited()
        
        find = False
        k = 0    
        v = 0 
        a = Source
        queue = []
        queue.append(a)
        path = []
        s_path = []
        
        while len(queue) > 0 and find == False:
            a = queue.pop(0)
            path.append(str(a))
            k = 0
            print "a : [" + str(a) + "]"
            while k < Node_List[a].NNeighbours and find == False:
                print "k : ->->->" + str(k)
                v = Node_List[a].NeighbourIndex[k]
                print "v : ->" + str(v)
                #if Node_List[v].Visited:
                if Node_List[v].Name == str(Destination):
                    find = True
                    path.append(Node_List[v].Name)
                else:
                    if v not in queue:
                        queue.append(v)    
                    k = k+1
                     
        if find == True:
            Node_List[Source].Set_Visited()
            #path[p] = Node_List[source].Name
            print "Find path...There it is : " + str(path)
            s_path = self.Backtrace_BFS(Node_List,path)
            print "Shortes path is : " + str(s_path)
            return True
        else:
            print "No path was found"
            return False    
    
    def Backtrace_BFS(self,Node_List,path):
        s_path = []
        l = (len(path)-1)
        s_path.append(path[l])
        find = False
        
        while l > 0:
            for i in range (0,l):
                print i
                print l 
                print path[l]
                print Node_List[i].NeighbourIndex
                if(path[l] in Node_List[i].NeighbourIndex):
                    print " ***_pass in if_***"
                    print Node_List[i].NeighbourIndex
                    s_path.append(path[l])
                    l = i
                    find = True
                    #print " ***_pass in if_***"
                else:
                    print " ***_pass in else_***"
                    find = False                        
            if find:
                pass
            else:
                l = l - 1
                print "New L : " + str(l)
        s_path.reverse()
        return s_path

    def Read(self, fname):
        try:
            f = open(fname, 'r')
        except:
            raise
            return
        
        self.N = int(f.readline().strip()) 
        d = f.readlines()
        for i in d:
            i = i.strip().split(" ")
            i = filter(lambda a: a != '', i)
            for n in range(0, len(i)):
                i[n] = int(i[n])
            self.Graph.append(i)
            
        f.close()
    
    def Reset_Graph(self):
        l = len(self.NodeList)
        for x in range(0,l):
            self.NodeList[x].Visited = False
        
    def Generate(self):
        self.Graph = [[-1 for j in xrange(self.N)] for i in xrange(self.N)]
        self.numL = [0 for i in xrange(self.N)]
        self.tpL = [0 for i in xrange(self.N)]
        
        
        for n in range(0,self.N):
            self.Graph[n][n] = 0
            try:
                self.numL[n] = self.minL + int(random() % (self.maxL - self.minL))
            except ZeroDivisionError:
                self.numL[n] = self.minL
            
        for k in range(1,self.minL):
            for n in range(0, self.N):
                if self.numL[n] > 0:
                    k = 0
                    for p in range(0, self.N):
                        if self.Graph[n][p] < 0 and self.numL[p] > 0:
                            self.tpL[k] = p
                            k += 1
                    if k>0:
                        a = self.tpL[int(random() % k)]
                        try:
                            p = self.minP + int(random() % (self.maxP-self.minP+1))
                        except ZeroDivisionError:
                            p = self.minP
                        self.Graph[n][a] = p                        
                        self.Graph[a][n] = p
                        self.numL[n] -= 1
                        self.numL[a] -= 1

    def __len__(self):
        return self.N
        
    def __str__(self):
        s = ''
       # s = [i for i in range(0,self.N)]
       # s = str(s) + "\n"
            
        for i in self.Graph:
            s += str(i)
            s += "\n"
        return s
    
    
if __name__ == "__main__":

    TestMode = True

    if TestMode:
        G = Graph(8,3,15,1,1)
        try:
            G.Generate()
            G.GenerateNodeList()
            path = []
            #G.BFS(G.NodeList,0,3,path,0)
        except:
            print 'Unable to open file'
        print G
    else:
        N = int(raw_input("N: "))
        minL = int(raw_input("minL: "))
        maxL = int(raw_input("maxL: "))
        minP = int(raw_input("minP: "))
        maxP = int(raw_input("maxP: "))
        G = Graph(N, minL, maxL, minP, maxP)
        G.Generate()
        print G
